home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
pctchnqs
/
1992
/
number2
/
rtcbios.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-16
|
12KB
|
320 lines
#pragma inline
/*
* RTCBIOS.C
* Interface module for the AT real-time clock functions 2
* through 7 and BIOS interrupt 15H functions 83H and 86H.
*
* Author Jim Mischel */
#include <dos.h>
#include <bios.h>
#include "rtcbios.h"
#define TESTING /* comment this if compiling for library */
#define ALARM 0x4A
/* SetWait -- Set a wait interval in microseconds.
* The interval is rounded up to the next multiple
* of 976 microseconds.
* At the end of the interval, the high bit or the byte
* pointed to by Flag will be set.
* Returns 0 if wait set successfully
* 1 if unable to set wait interval */
int SetWait (long ms, unsigned char far *Flag) {
char Status;
*Flag &= 0x7f; /* clear flag */
asm mov ax,8300h
asm mov cx,[word ptr ms+2] /* CX:DX = wait interval... */
asm mov dx,[word ptr ms] /* ...in microseconds */
asm les bx,[Flag] /* ES:BX=address of flag */
asm clc /* clear status */
asm int 15h /* set the wait */
asm lahf /* put flags into AH */
asm and ah,1 /* get Carry flag (bit 0) */
asm mov [Status],ah /* save status... */
return Status; /* ...and exit */
}
/* CancelWait -- Cancel wait interval set by SetWait. */
void CancelWait (void) {
asm mov ax,0040h
asm mov es,ax /* ES = BIOS data segment */
asm cli /* no interruptions! */
asm xor ax,ax /* clear... */
asm mov [byte ptr es:00A0h],al /* Wait Active flag... */
asm mov [word ptr es:009Ch],ax /* ...LSB and... */
asm mov [word ptr es:009Eh],ax /* MSB of Wait Count */
asm sti
}
/* Wait -- Delay execution for a number of microseconds.
* Wait interval is rounded up to the next multiple
* of 976 microseconds.
* Returns 0 if wait successful
* 1 if unable to wait for the interval */
int Wait (long ms) {
char Status;
asm mov ah,86h
asm mov cx,[word ptr ms+2] /* CX:DX = wait interval... */
asm mov dx,[word ptr ms] /* ...in microseconds */
asm int 15h /* do the wait */
asm lahf /* get flags into AH */
asm and ah,1 /* Carry flag is bit 0... */
asm mov [Status],ah /* ...and save as Status */
return Status;
}
/* BCDtoBin - Convert BCD value (0-99) to binary */
static int BCDtoBin (int BCD) {
return (BCD >> 4)*10 + (BCD & 0xf);
}
/* Convert binary value (0-99) to BCD */
static int BinToBCD (int Bin) {
return ((Bin / 10) << 4) + (Bin % 10);
}
/* GetRTCtime -- Get current RTC time & place in Time structure.
* Returns 0 -- function successful
* 1 -- unable to read time (Time invalid) */
int GetRTCtime (struct RTCTIME far *Time) {
char Status;
asm mov ah,2 /* Read RTC time function */
asm clc /* clear status indicator */
asm int 1ah /* go read the time */
asm lahf /* get flags to AH */
asm and ah,1 /* get status of carry flag... */
asm mov [Status],ah /* ...and store in Status */
asm jnz around /* if not successful, skip */
asm les di,[Time] /* ES:DI = address of time structure */
asm xor ah,ah
asm mov [es:di+6],ax /* save daylight flag */
asm mov al,ch
asm cld
asm stosw /* Hour,... */
asm mov al,cl
asm stosw /* ...Minute,... */
asm mov al,dh
asm stosw /* ...and Second */
/* -- Convert returned time from BCD to binary -- */
Time->Hour = BCDtoBin (Time->Hour);
Time->Min = BCDtoBin (Time->Min);
Time->Sec = BCDtoBin (Time->Sec);
around:
return Status;
}
/* SetRTCtime -- Set current time from Time structure
* Returns 0 -- function successful
* 1 -- unable to set time (Time invalid) */
int SetRTCtime (struct RTCTIME *Time) {
char Status;
struct RTCTIME WorkTime;
/* -- Convert Time to BCD in WorkTime -- */
WorkTime.Hour = BinToBCD (Time->Hour);
WorkTime.Min = BinToBCD (Time->Min);
WorkTime.Sec = BinToBCD (Time->Sec);
WorkTime.Daylight = Time->Daylight;
asm mov ah,3 /* set RTC Time function */
asm mov ch,[WorkTime.Hour]
asm mov cl,[WorkTime.Min]
asm mov dh,[WorkTime.Sec]
asm mov dl,[WorkTime.Daylight]
asm clc
asm int 1ah
asm lahf /* get flags to AH */
asm and ah,1 /* carry flag is bit 0... */
asm mov [Status],ah /* ...and store in Status */
return Status;
}
/* GetRTCdate -- Get RTC date and place in Date structure.
* Returns 0 -- function successful
* 1 -- unable to read date */
int GetRTCdate (struct RTCDATE far *Date) {
char Status;
asm mov ah,4 /* Get RTC date function */
asm clc /* clear status indicator */
asm int 1ah /* go read the date */
asm lahf /* get flags to AH */
asm and ah,1 /* get status of carry flag... */
asm mov [Status],ah /* ...and store in Status */
asm jnz around /* if not successful, skip */
asm les di,[Date] /* ES:DI = address of date structure */
asm xor ax,ax
asm cld
asm mov al,ch
asm stosw /* Save century,... */
asm mov al,cl
asm stosw /* ...year,... */
asm mov al,dh
asm stosw /* ...month,... */
asm mov al,dl
asm stosw /* ...and day */
/* -- Convert returned date from BCD to binary -- */
Date->Century = BCDtoBin (Date->Century);
Date->Year = BCDtoBin (Date->Year);
Date->Month = BCDtoBin (Date->Month);
Date->Day = BCDtoBin (Date->Day);
around:
return Status;
}
/* SetRTCdate -- Set RTC date from Date structure
* Returns 0 -- function successful
* 1 -- unable to set date */
int SetRTCdate (struct RTCDATE *Date) {
char Status;
struct RTCDATE WorkDate;
/* -- Convert Date to BCD in WorkDate -- */
WorkDate.Century = BinToBCD (Date->Century);
WorkDate.Year = BinToBCD (Date->Year);
WorkDate.Month = BinToBCD (Date->Month);
WorkDate.Day = BinToBCD (Date->Day);
asm mov ah,5 /* set RTC Date function */
asm mov ch,[WorkDate.Century]
asm mov cl,[WorkDate.Year]
asm mov dh,[WorkDate.Month]
asm mov dl,[WorkDate.Day]
asm clc
asm int 1ah
asm lahf /* get flags to AH */
asm and ah,1 /* carry flag is bit 0... */
asm mov [Status],ah /* ...and store in Status */
return Status;
}
/* SetAlarm -- Set the user alarm from the Time structure and
* install the alarm interrupt service routine.
* Returns 0 if alarm set successfully
* 1 if unable to set alarm. */
int SetAlarm (struct RTCTIME *Time,
void interrupt (*AlarmInt)()) {
char Status;
struct RTCTIME WorkTime;
/* -- Convert Time to BCD in WorkTime -- */
WorkTime.Hour = BinToBCD (Time->Hour);
WorkTime.Min = BinToBCD (Time->Min);
WorkTime.Sec = BinToBCD (Time->Sec);
asm mov ah,6 /* set alarm function */
asm mov ch,[WorkTime.Hour]
asm mov cl,[WorkTime.Min]
asm mov dh,[WorkTime.Sec]
asm clc /* fixes problem with some BIOS */
asm int 1ah
asm lahf /* get flags to AH */
asm and ah,1 /* carry flag is bit 0... */
asm mov [Status],ah /* ...and store in Status */
if (!Status)
setvect (ALARM, AlarmInt); /* install new ISR */
return Status;
}
/* ClearAlarm -- Cancel alarm set by SetAlarm */
void ClearAlarm (void) {
asm mov ah,7
asm int 1ah
}
/*** Test code ***/
#ifdef TESTING
#include <stdio.h>
#define ESC 0x011B
volatile int TimeOut; /* Flag set by alarm ISR */
void interrupt (*OldAlarmInt) (void) = NULL; /* old alarm ISR */
/* AlarmInterrupt -- Sets the TimeOut flag and returns */
void interrupt AlarmInterrupt (void) {
#ifdef __TINY__
asm extrn DGROUP@ /* Fix problem with TC++ Tiny model */
#endif
TimeOut = 1;
}
/* Make a simple sound effect */
void SoundAlarm (void) {
static int FreqTable[] = {238,265,298,341,398,477,597,0};
int Freq;
for (Freq = 0; FreqTable[Freq] != 0; Freq++) {
sound (FreqTable[Freq]);
Wait (300000L/(Freq+1));
}
nosound ();
}
void main (void) {
unsigned char KeyFlag; /* flag used by SetWait */
int ch; /* dummy variable to read key */
struct RTCTIME Time;
struct RTCDATE Date;
/* Part 1 -- test Wait, SetWait, CancelWait */
do {
KeyFlag = 0;
while (bioskey (1)) /* empty keyboard buffer */
ch = bioskey (0);
/* -- 2.5 second wait interval -- */
if (SetWait (2500000L, &KeyFlag))
puts ("Unable to set wait interval");
printf ("Press any key.\n"
"Press ESC to move to 2nd part of test: ");
ch = bioskey (0); /* wait for character */
CancelWait (); /* cancel wait interval */
if (KeyFlag & 0x80) /* wait interval expired? */
puts ("Key pressed AFTER wait interval expired.\n");
else
puts ("Key pressed during wait interval.\n");
if (Wait (1000000L)) /* 1-second delay */
puts ("Wait error");
} while (ch != ESC); /* loop until ESC */
/* Part 2: Test GetRTCtime, GetRTCdate, SetAlarm, ClearAlarm */
if (GetRTCdate (&Date))
puts ("Unable to read RTC date");
else
printf ("Today is %02d/%02d/%02d%02d\n",
Date.Month, Date.Day, Date.Century, Date.Year);
if (GetRTCtime (&Time))
puts ("Unable to read RTC time");
else {
printf ("The time is %02d:%02d:%02d\n",
Time.Hour, Time.Min, Time.Sec);
if (Time.Daylight > 1)
puts ("Status of daylight savings "
"flag is undetermined");
else
printf ("Daylight savings time %s in effect\n",
(Time.Daylight) ? "is" : "is not");
/* -- add 30 seconds to the current time -- */
Time.Sec = Time.Sec + 30;
if (Time.Sec > 59) {
Time.Sec -= 60;
if (++Time.Min > 59) {
Time.Min -= 60;
if (++Time.Hour > 23)
Time.Hour -= 24;
}
}
OldAlarmInt = getvect (ALARM); /* Save old alarm int */
TimeOut = 0;
if (SetAlarm (&Time, AlarmInterrupt))
puts ("Unable to set alarm");
else {
printf ("Alarm will sound at %02d:%02d:%02d\n",
Time.Hour, Time.Min, Time.Sec);
puts ("Press any key to exit"
" before alarm sounds");
while (!TimeOut) { /* Wait for alarm */
if (bioskey (1)) { /* if key pressed */
bioskey (0); /* read key... */
break; /* ...and exit loop */
}
}
SoundAlarm (); /* sound the alarm */
ClearAlarm (); /* turn alarm off */
}
setvect (ALARM, OldAlarmInt); /* reset alarm int */
}
}
#endif TESTING